#include "zbComm.h"

u16 RxCounter = 0;
CircularBuffer rxUSCBuff;
u8 byteBuffer[bufferSize];
u8 rxByte = 0; // current rx byte

void initComm()
{
	NVIC_InitTypeDef 		NVIC_InitStructure;

	// init clocks
	RCC_APB1PeriphClockCmd(zbCom_USART_TX_GPIO_CLK, ENABLE); 
	RCC_APB1PeriphClockCmd(zbCom_USART_RX_GPIO_CLK, ENABLE); 
	RCC_APB1PeriphClockCmd(zbCom_USART_CLK,ENABLE);
	RCC_AHB1PeriphClockCmd(zbCom_Usart_DMA_CLK, ENABLE);

	// int our vector table
		/* Enable the DMA Stream IRQ Channel */
	NVIC_InitStructure.NVIC_IRQChannel = zbCom_DMA_STREAM_IRQ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure); 
		/* Enable the USARTz Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = zbCom_USART_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	// init circular buffer
	cbInit(&rxUSCBuff);
  	// --- config for usart comm

	// init the usart output 
	USART2_Config();

	// init the dma for usart tx
	//initDMA2();
}

void cbInit(CircularBuffer *cb) {
	cb->elems = byteBuffer;
    cb->size  = bufferSize; /* include empty elem */
    cb->start = 0;
    cb->count = 0;
}
 
int cbIsFull(CircularBuffer *cb) {
    return cb->count == cb->size; }
 
int cbIsEmpty(CircularBuffer *cb) {
    return cb->count == 0; }

int cbCount(CircularBuffer *cb) {
    return cb->count; }
 
void cbWrite(CircularBuffer *cb, u8 *elem) {
    int end = (cb->start + cb->count) % cb->size;
    cb->elems[end] = *elem;
    if (cb->count == cb->size)
        cb->start = (cb->start + 1) % cb->size; /* full, overwrite */
    else
        ++ cb->count;
}
 
void cbRead(CircularBuffer *cb, u8 *elem) {
    *elem = cb->elems[cb->start];
    cb->start = (cb->start + 1) % cb->size;
    -- cb->count;
}

/**
  * @brief 
  *       
  *         
  * @note   
  * @param  none
  * @retval none
  */
void USART2_Config(void)
{
	USART_InitTypeDef 		USART_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure; 
	
	GPIO_InitStructure.GPIO_Pin = zbCom_USART_TX_PIN | zbCom_USART_RX_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(zbCom_USART_TX_GPIO_PORT, &GPIO_InitStructure);

	GPIO_PinAFConfig(zbCom_USART_TX_GPIO_PORT, zbCom_USART_TX_SOURCE, zbCom_USART_TX_AF);
	GPIO_PinAFConfig(zbCom_USART_RX_GPIO_PORT, zbCom_USART_RX_SOURCE, zbCom_USART_RX_AF);
	
	USART_InitStructure.USART_BaudRate = zbCom_USART_BAUD;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(zbCom_USART, &USART_InitStructure);
	
	// hold onto your butts
	USART_Cmd(zbCom_USART, ENABLE);
}

void USART2_IRQHandler(void)
{
	// if we get overrun 
	if(USART_GetFlagStatus(zbCom_USART, USART_FLAG_ORE) != RESET)
	{
		rxByte = USART_ReceiveData(zbCom_USART);
	}
	// if we are here because it rxne then store the data
	if(USART_GetITStatus(zbCom_USART, USART_IT_RXNE) != RESET)
	{
			// read dr to clear all flags
			rxByte = USART_ReceiveData(zbCom_USART);
 			cbWrite(&rxUSCBuff, &rxByte);
			
			//if(cbIsFull(&rxUSCBuff))
			//{
				/* Disable the USARTy Receive interrupt */
				//USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
				// mark buffer overflow
			//	mygVars->status |= ERR_PKT_OF;
			//}
			//USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	}
	//USART_ClearFlag(USART2,USART_FLAG_RXNE);
}

void BASIC_TXPush(void)
{
	u8 *dataPointer = 0;
	u16 i=0;
	
	if(dmaTX.state == new)
	{
		// send out header
		dataPointer = dmaTX.txHdr;
		for(i=0; i<hdrSize; i++)
		{
			USART_SendData(zbCom_USART, dataPointer[i]);
			while (USART_GetFlagStatus(zbCom_USART, USART_FLAG_TC) == RESET)
			{}
		}
	
		// send out data 
		dataPointer = dmaTX.offset;
		for(i=0; i<dmaTX.count; i++)
		{
			USART_SendData(zbCom_USART, dataPointer[i]);
			while (USART_GetFlagStatus(zbCom_USART, USART_FLAG_TC) == RESET)
	  		{}
		}
	
		dmaTX.state = done;
	}
}

void DMA_TXPush(void)
{
	DMA_InitTypeDef 		DMA_InitStructure;
	u8 *dataPointer = 0;
	u16 len = 0;
	
	if(dmaTX.state == done)
	return;
	if(dmaTX.state == data)
	{
	dmaTX.state = done;
	dataPointer = dmaTX.offset;
	len = dmaTX.count;
	}
	if(dmaTX.state == new)
	{
	dmaTX.state = data;
	dataPointer = dmaTX.txHdr;
	len = hdrSize;
	}
	
	/* USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config */
	DMA_DeInit(zbCom_Usart_DMA_Stream);
	  /* Check if the DMA Stream is disabled before enabling it.
	 Note that this step is useful when the same Stream is used multiple times:
	 enabled, then disabled then re-enabled... In this case, the DMA Stream disable
	 will be effective only at the end of the ongoing data transfer and it will
	 not be possible to re-configure it before making sure that the Enable bit
	 has been cleared by hardware. If the Stream is used only once, this step might
	 be bypassed. */
	while (DMA_GetCmdStatus(zbCom_Usart_DMA_Stream) != DISABLE)
	{
	}
	DMA_InitStructure.DMA_Channel = zbCom_DMA_CHANNEL;
	DMA_InitStructure.DMA_PeripheralBaseAddr = zbCom_DRADDR;	// usart2 data register
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dataPointer;
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; 
	DMA_InitStructure.DMA_BufferSize = len;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	
	DMA_Init(zbCom_Usart_DMA_Stream, &DMA_InitStructure);
	
	USART_DMACmd(zbCom_USART, USART_DMAReq_Tx, ENABLE);
	
	/* Enable DMA Stream Half Transfer and Transfer Complete interrupt */
	DMA_ITConfig(zbCom_Usart_DMA_Stream, DMA_IT_TC, ENABLE);
	
	// start the dma transfer, it will execute now
	DMA_Cmd(zbCom_Usart_DMA_Stream, ENABLE);
}

/**
  * @brief 
  *       
  *         
  * @note   
  * @param  none
  * @retval none
  */
void DMA1_Stream6_IRQHandler(void)
{
	/*
  *            @arg DMA_IT_TCIFx:  Streamx transfer complete interrupt
  *            @arg DMA_IT_HTIFx:  Streamx half transfer complete interrupt
  *            @arg DMA_IT_TEIFx:  Streamx transfer error interrupt
  *            @arg DMA_IT_DMEIFx: Streamx direct mode error interrupt
  *            @arg DMA_IT_FEIFx:  Streamx FIFO error interrupt	*/
  //if(DMA_GetITStatus(zbCom_Usart_DMA_Stream, DMA_IT_TEIF0|DMA_IT_DMEIF0|DMA_IT_FEIF0))
  //{
  //		  printf("USART DMA ERROR");
  //		  return; // fail
  // }
  /* Test on DMA Stream Transfer Complete interrupt */
  if(DMA_GetITStatus(zbCom_Usart_DMA_Stream, zbCom_DMA_FLAG_TC))
  {
    /* Clear DMA Stream Transfer Complete interrupt pending bit */
    DMA_ClearITPendingBit(zbCom_Usart_DMA_Stream, zbCom_DMA_FLAG_TC);  

  }

	if(dmaTX.state != done)
	{
		DMA_TXPush();
	}else{
		DMA_DeInit(zbCom_Usart_DMA_Stream);
	}
}

void testComm(void)
{
	u8 i = 0;											

	while(debugChar == 't')
	{
		USART_SendData(zbCom_USART,'T');
		Delay(1000);

		printf("\n\r || USART2->SR:0x%x USART2->CR1:0x%x ", USART2->SR, USART2->CR1 );

		i++;
	}
}

